package com.ml.config;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;
/**
 * 
 * @author Virgil
 * @Date 2018年8月18日
 * @Describe
 *    <p>
 *		线程池
 *    </p>
 */
@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableScheduling
@Slf4j
public class TaskExecutorConfig implements AsyncConfigurer, SchedulingConfigurer {

	@Bean
	public TaskExecutor taskExecutor() {
		log.info("初始化Async线程池");
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		// 获取JAVA虚拟机的可用处理器数量。IO密集型建议核心线程数是该值2倍；计算密集型建议核心线程数是该值1倍
		int processorNum = Runtime.getRuntime().availableProcessors();
		// 设置核心线程数量。若池中的实际线程数小于该值，无论其中是否有空闲的线程，都会产生新的线程
		executor.setCorePoolSize(processorNum * 2);
		// 设置最大线程数量
		executor.setMaxPoolSize(processorNum * 4);
		// 设置阻塞任务队列大小
		executor.setQueueCapacity(100);
		// 线程名称前缀
		executor.setThreadNamePrefix("vrigil-Async-");
		// 设置线程池中任务的等待时间，若超过等待时间仍未销毁则强制销毁，以确保应用最后能够被关闭，而不是阻塞住
		executor.setAwaitTerminationSeconds(1);
		// 设置拒绝策略，当线程池阻塞队列已满时对新任务的处理。调节机制，即饱和时回退主线程执行
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	}

	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return (throwable, method, params) -> {
			log.error("异步任务异常：方法：{} 参数：{}", method.getName(), JSON.toJSONString(params));
			log.error(throwable.getMessage(), throwable);
		};
	}

	@Override
	public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
		log.info("初始化Scheduled线程池");
		taskRegistrar.setScheduler(new ScheduledThreadPoolExecutor(10, new ThreadFactory() {
			private AtomicInteger max = new AtomicInteger(0);

			@Override
			public Thread newThread(Runnable runnable) {
				return new Thread(runnable, "vrigil-Scheduled-" + max.incrementAndGet());
			}
		}));
	}
}
